/*
 * $Id: CalendarCellContext.java 3286 2009-03-10 12:13:43Z kleopatra $
 *
 * Copyright 2007 Sun Microsystems, Inc., 4150 Network Circle,
 * Santa Clara, California 95054, U.S.A. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */
package org.jdesktop.swingx.plaf.basic;

import java.awt.Color;
import java.util.Calendar;

import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.Border;

import org.jdesktop.swingx.JXMonthView;
import org.jdesktop.swingx.border.IconBorder;
import org.jdesktop.swingx.plaf.UIManagerExt;
import org.jdesktop.swingx.renderer.CellContext;

/**
 * MonthView specific CellContext. This is internally used by BasisMonthViewUI
 * rendering.
 * 
 * @author Jeanette Winzenburg
 */
class CalendarCellContext extends CellContext {

	/**
	 * The padding for month traversal icons. PENDING JW: decouple rendering and
	 * hit-detection. As is, these are hard-coded "magic numbers" which must be
	 * the same in both the ui-delegate (which does the hit-detection) and here
	 * (which returns the default title border)
	 * 
	 * Added as preliminary fix for #1028-swingx: title border incorrect if
	 * box-padding 0
	 */
	private int arrowPaddingX = 3;
	private int arrowPaddingY = 3;

	private CalendarState dayState;

	public void installContext(JXMonthView component, Calendar value, boolean selected, boolean focused, CalendarState dayState) {
		this.component = component;
		this.dayState = dayState;
		installState(value, -1, -1, selected, focused, true, true);
	}

	@Override
	public JXMonthView getComponent() {
		return (JXMonthView) super.getComponent();
	}

	public CalendarState getCalendarState() {
		return dayState;
	}

	public Calendar getCalendar() {
		return (getValue() instanceof Calendar) ? (Calendar) getValue() : null;
	}

	@Override
	protected Color getForeground() {
		if (CalendarState.LEADING == dayState) {
			return getUIColor("leadingDayForeground");
		}
		if (CalendarState.TRAILING == dayState) {
			return getUIColor("trailingDayForeground");
		}
		if ((CalendarState.TITLE == dayState) && (getComponent() != null)) {
			return getComponent().getMonthStringForeground();
		}
		if (CalendarState.WEEK_OF_YEAR == dayState) {
			Color weekOfTheYearForeground = getUIColor("weekOfTheYearForeground");
			if (weekOfTheYearForeground != null) {
				return weekOfTheYearForeground;
			}
		}
		if (CalendarState.DAY_OF_WEEK == dayState) {
			Color daysOfTheWeekForeground = getComponent() != null ? getComponent().getDaysOfTheWeekForeground() : null;
			if (daysOfTheWeekForeground != null) {
				return daysOfTheWeekForeground;
			}
		}

		Color flaggedOrPerDayForeground = getFlaggedOrPerDayForeground();
		return flaggedOrPerDayForeground != null ? flaggedOrPerDayForeground : super.getForeground();
	}

	/**
	 * @param key
	 * @return
	 */
	private Color getUIColor(String key) {
		return UIManagerExt.getColor(getUIPrefix() + key);
	}

	/**
	 * Returns the special color used for flagged days or per weekday or null if
	 * none is set, the component or the calendar are null.
	 * 
	 * @return the special foreground color for flagged days or per dayOfWeek.
	 */
	protected Color getFlaggedOrPerDayForeground() {

		if (getComponent() != null && (getCalendar() != null)) {
			if (getComponent().isFlaggedDate(getCalendar().getTime())) {
				return getComponent().getFlaggedDayForeground();
			} else {
				Color perDay = getComponent().getPerDayOfWeekForeground(getCalendar().get(Calendar.DAY_OF_WEEK));
				if (perDay != null) {
					return perDay;
				}

			}
		}
		return null;
	}

	@Override
	protected Color getBackground() {
		if ((CalendarState.TITLE == dayState) && (getComponent() != null)) {
			return getComponent().getMonthStringBackground();
		}
		return super.getBackground();
	}

	@Override
	protected Color getSelectionBackground() {
		if (CalendarState.LEADING == dayState || CalendarState.TRAILING == dayState)
			return getBackground();
		return getComponent() != null ? getComponent().getSelectionBackground() : null;
	}

	@Override
	protected Color getSelectionForeground() {
		if (CalendarState.LEADING == dayState || CalendarState.TRAILING == dayState)
			return getForeground();
		Color flaggedOrPerDayForeground = getFlaggedOrPerDayForeground();
		if (flaggedOrPerDayForeground != null) {
			return flaggedOrPerDayForeground;
		}
		return getComponent() != null ? getComponent().getSelectionForeground() : null;
	}

	@Override
	protected Border getBorder() {
		if (getComponent() == null) {
			return super.getBorder();
		}
		if (CalendarState.TITLE == dayState) {
			return getTitleBorder();
		}
		if (isToday()) {
			int x = getComponent().getBoxPaddingX();
			int y = getComponent().getBoxPaddingY();
			Border todayBorder = BorderFactory.createLineBorder(getComponent().getTodayBackground());
			Border empty = BorderFactory.createEmptyBorder(y - 1, x - 1, y - 1, x - 1);
			return BorderFactory.createCompoundBorder(todayBorder, empty);
		}
		return BorderFactory.createEmptyBorder(getComponent().getBoxPaddingY(), getComponent().getBoxPaddingX(), getComponent()
				.getBoxPaddingY(), getComponent().getBoxPaddingX());
	}

	/**
	 * @return
	 */
	private Border getTitleBorder() {
		if (getComponent().isTraversable()) {
			Icon downIcon = UIManager.getIcon("JXMonthView.monthDownFileName");
			Icon upIcon = UIManager.getIcon("JXMonthView.monthUpFileName");

			// fix for #1028-swingx: title border whacky for boxpadding 0
			// in fact there had been a deeper issue - without using the
			// arrowPadding here
			// the hit-detection of the buttons is slightly off target
			IconBorder up = new IconBorder(upIcon, SwingConstants.EAST, arrowPaddingX);
			IconBorder down = new IconBorder(downIcon, SwingConstants.WEST, arrowPaddingX);
			Border compound = BorderFactory.createCompoundBorder(up, down);
			Border empty = BorderFactory.createEmptyBorder(2 * arrowPaddingY, 0, 2 * arrowPaddingY, 0);
			return BorderFactory.createCompoundBorder(compound, empty);
		}

		return BorderFactory.createEmptyBorder(getComponent().getBoxPaddingY(), getComponent().getBoxPaddingX(), getComponent()
				.getBoxPaddingY(), getComponent().getBoxPaddingX());
	}

	/**
	 * @return
	 */
	protected boolean isToday() {
		return CalendarState.TODAY == dayState;
	}

	@Override
	protected String getUIPrefix() {
		return "JXMonthView.";
	}

}
